﻿//*******************************************************************************
//
//					ProjectName	 :		
//					
//					SpriteName	 :		LoopList
//
//					SpriteExplain: 	    循环列表
//					
//			
//*******************************************************************************

using System.Collections.Generic;
using UnityEngine;

public class LoopList : MonoBehaviour {

   public class Rollingitem
    {
        /// <summary>
        /// 上一个
        /// </summary>
        public Rollingitem Upper;
        /// <summary>
        /// 下一个
        /// </summary>
        public Rollingitem Next;

        public Transform   Target;
        /// <summary>
        /// 竖向索引
        /// </summary>
        public int Vindex;
        /// <summary>
        /// 横向索引
        /// </summary>
        public int HIndex;
        /// <summary>
        /// ID
        /// </summary>
        public int Id;
//        public int Index { get; private set; }
    }

    public enum MoveType {
        None = 0,
        Upper = -1,
        Next = 1,
    }

    public enum RollType {
        Horizontal = 0,
        Vertical,
    }

    #region 公开属性
    public RollType Type = RollType.Vertical;
    public int Hight = 100;
    public int Width = 100;
    public int ColumnLimit = 0;

    public int Count { get; private set; }

    /// <summary>
    ///  移动回调
    /// </summary>
    /// <param name="move">移动类型 （上下）</param>
    /// <param name="claer">需要清空的 项</param>
    /// <param name="target">目标</param>
    public delegate void MoveChnage(MoveType move, int claer, int oneStart, int oneIndex, Transform target);
    public MoveChnage MoveChange;

    public int ViewNum {
        get { return _viewNum; }
    }

    public Rollingitem MinItem
    {
        get { return _minHight; }
    }

    public Rollingitem OneItem
    {
        get { return _oneItem; }
    }
    #endregion

    #region 私有属性
    /// <summary>
    /// 可以显示的数量
    /// </summary>
    private int _viewNum;
    /// <summary>
    /// 处于最高位置的 item
    /// </summary>
    private Rollingitem _maxHight;
    /// <summary>
    /// 处于最低位置的 item
    /// </summary>
    private Rollingitem _minHight;
    /// <summary>
    /// 位于第一行的
    /// </summary>
    private Rollingitem _oneItem;
    /// <summary>
    /// 目标滑动 通过控制 panel 的offset 偏移值
    /// </summary>
    private UIPanel _panel;

    // 滑动控制
    private UIScrollView _view;

    public UIScrollView View
    {
        get { return _view; }
    }
    /// <summary>
    ///  记录panel 初始坐标 
    /// 
    /// 用于重置panel 坐标
    /// </summary>
    protected Vector3 CachePanelPos;
    /// <summary>
    /// 记录panel 偏移坐标
    /// 
    /// 用于重置panel 坐标
    /// </summary>
    protected Vector2 CachePanelOffset;

    /// <summary>
    /// 高度限制  ->Vertical
    /// 
    /// 判断是否允许切换 数据条的位置
    /// </summary>
    protected float HightCritical;
    /// <summary>
    /// 宽度限制  -> Horizontal
    /// 
    ///  判断是否允许切换 数据条的位置
    /// </summary>
    protected float WidthCritical;
    #endregion

    #region 初始化
    public void OnStart()
    {
        _panel = FindUIPanel<UIPanel>(transform);
        if (_panel == null) {
            Debug.LogError("错误没有找到 UIPanel");
            return;
        }
        _view = _panel.GetComponent<UIScrollView>();
        _view.DisableSpring();
        _panel.onClipMove = OnClipMove;

        CachePanelPos     = _panel.transform.localPosition;
        CachePanelOffset  = _panel.clipOffset;
        Reset();
    }
    #endregion

    #region 重置
    /// <summary>
    /// 重置
    /// </summary>
    public void Reset() {
        Count             = transform.childCount;
        _view.enabled     = false;
        _panel.onClipMove = null;

        // 建立 双向列表

        // 未完成多列
        Rollingitem now = null;
        _maxHight = null;
        for (int i = 0; i < Count; i++) {
            Rollingitem item = new Rollingitem
            {
                Id = i,
                Vindex = i,
                Target = transform.GetChild(i),
                Next = null
            };
            if (_maxHight == null) {
                item.Upper = null;
                item.Next = null;
                _maxHight = item;
                now = _maxHight;
                continue;
            }
            //上一个
            item.Upper = now;
            //下一个
            if (now != null)
                now.Next = item;

            now = item;
        }
       _minHight = now;


       // 缓存 panel的 坐标和偏移
       _panel.transform.localPosition = CachePanelPos;
       _panel.clipOffset              = CachePanelOffset;

       // 计算横向 竖向 边界限制
       var maxHight = Hight * Count;
       var maxWidth = Width * Count;

       HightCritical = maxHight * 0.5f;
       WidthCritical = maxWidth * 0.5f;


        // 计算 控件坐标
       if (Type == RollType.Horizontal) {
           _view.movement = UIScrollView.Movement.Horizontal;
           float nowWidth = _panel.baseClipRegion.z * 0.5f + Width * 0.5f - Width;
           // 显示 数量加预显示缓存数量
           _viewNum = Mathf.RoundToInt(_panel.baseClipRegion.z / Width);
           //            _viewNum
           for (int i = 0; i < Count; i++)
           {
               var tr = transform.GetChild(i);
               tr.localPosition = new Vector3(nowWidth, 0, 0);
               nowWidth -= Width;
           }
           var mycount = Count;
           while (OnHorizontalMove() != MoveType.None) {
               if (--mycount < 0) {
                   Debug.LogError("错误出现死循环");
                   break;
               }
           }
       } else {
           _view.movement = UIScrollView.Movement.Vertical;
           float nowHight = _panel.baseClipRegion.w * 0.5f + Hight * 0.5f - Hight;

           // 显示 数量加预显示缓存数量
           _viewNum = Mathf.RoundToInt(_panel.baseClipRegion.w / Hight);
           for (int i = 0; i < Count; i++) {
               var tr = transform.GetChild(i);
               tr.localPosition = new Vector3(0, nowHight, 0);
               nowHight -= Hight;
           }
           var mycount = Count;
           while (OnVerticalMove() != MoveType.None) {
               if (--mycount < 0) {
                   Debug.LogError("错误出现死循环");
                   break;
               }
           }
       }   
       // 查找并记录 处于第一行的记录
       Rollingitem oneItem = _maxHight;
       while (true) {
           if (oneItem == null)
               break;

           if (oneItem.Id == 0) {
               _oneItem = oneItem;
               break;
           }
           oneItem = oneItem.Next;
           if (oneItem != null) continue;

           Debug.Log("编号错误");
           break;
       }
       _panel.onClipMove = OnClipMove;
       _view.enabled     = true;
    }
    #endregion

    #region 组件查找 索引计算
    private T FindUIPanel<T>(Transform tr) where T : Component {

        Transform tar = tr;

        while (!tar.GetComponent<T>()) {
            if (tar.parent == null) break;
            tar = tar.parent;
        }
        return tar.GetComponent<T>();
    }
    public int UpdateIndex(int value) {
        if (value >= 0)
            return value % Count;
        return Count + ( value % Count );
    }

    #endregion

    #region  拖动
    private void OnClipMove(UIPanel panel) {

        if (Type == RollType.Vertical) OnVerticalMove();
       
        else OnHorizontalMove();
    }

    protected virtual MoveType OnHorizontalMove() {
        MoveType type = MoveType.None;

        if (_maxHight.Target.localPosition.x - _panel.clipOffset.x > WidthCritical) {

            // 计算坐标
            var pos = _maxHight.Target.localPosition;
            pos.x = _minHight.Target.localPosition.x - Width;
            _maxHight.Target.localPosition = pos;
            //切换链表
            UpAndDownSwitch();
            type = MoveType.Next;
            if (_oneItem != null) DownSwitch(ref _oneItem);
            
            if (MoveChange != null && _oneItem != null) 
                MoveChange(type, _minHight.Vindex, _oneItem.Vindex, _oneItem.Id, _oneItem.Target);
            

        } else if (_minHight.Target.localPosition.x - _panel.clipOffset.x < -WidthCritical) {
            // 计算坐标
            var pos = _minHight.Target.localPosition;
            pos.x   = _maxHight.Target.localPosition.x + Width;
            _minHight.Target.localPosition = pos;
            //切换链表
            DownAndUpSwitch();

            if (_oneItem != null) UpSwitech(ref _oneItem);

            if (MoveChange != null && _oneItem != null) 
                MoveChange(type, _maxHight.Vindex, _oneItem.Vindex, _oneItem.Id, _oneItem.Target);
            
        }

        return type;
    }

    protected virtual MoveType OnVerticalMove() {
        MoveType type = MoveType.None;

        if (_maxHight.Target.localPosition.y - _panel.clipOffset.y > HightCritical ) { 
            
            // 计算坐标
            var pos = _maxHight.Target.localPosition;
            pos.y   = _minHight.Target.localPosition.y - Hight;
            _maxHight.Target.localPosition = pos;
            //切换链表
            UpAndDownSwitch();
            type = MoveType.Next;
            if (_oneItem != null) DownSwitch(ref _oneItem); 
            
            if (MoveChange != null && _oneItem != null)      
                MoveChange(type, _minHight.Vindex, _oneItem.Vindex,_oneItem.Id, _oneItem.Target);
            

        } else if (_minHight.Target.localPosition.y - _panel.clipOffset.y < -HightCritical) {
            // 计算坐标
            var pos = _minHight.Target.localPosition;
            pos.y   = _maxHight.Target.localPosition.y + Hight;
            _minHight.Target.localPosition = pos;
            //切换链表
            DownAndUpSwitch();

            type    = MoveType.Upper;
            if (_oneItem != null) UpSwitech(ref _oneItem);

            if (MoveChange != null && _oneItem != null) 
                MoveChange(type, _maxHight.Vindex, _oneItem.Vindex, _oneItem.Id, _oneItem.Target);
            
        }

        return type;
    }
    #endregion

    #region  链表更新
    /// <summary>
    /// 向下切换
    /// </summary>
    void DownSwitch(ref Rollingitem item)
    {
        item = item.Next;
    }
    /// <summary>
    /// 向上切换
    /// </summary>
    /// <param name="item"></param>
    void UpSwitech(ref Rollingitem item)
    {
        item = item.Upper;

    }
    /// <summary>
    /// 链表上下切换  最上边的切换到最先
    /// </summary>
    void UpAndDownSwitch()
    {
        Rollingitem item = _maxHight;
        _maxHight         = _maxHight.Next;
        _maxHight.Upper   = null;

        item.Next      = null;

        item.Upper     = _minHight;
        item.Id        = _minHight.Id + 1;
        _minHight.Next = item;
        _minHight      = item;
    }

    /// <summary>
    /// 链表下上切换  最下边的切换到最上边
    /// </summary>
    void DownAndUpSwitch()
    {
        Rollingitem item = _minHight;

        _minHight      = _minHight.Upper;
        _minHight.Next = null;

        item.Upper     = null;
        item.Next      = _maxHight;
        item.Id     = _maxHight.Id - 1;
        _maxHight.Upper = item;
        _maxHight       = item;

    }
    #endregion

    public void Clear() {

        if (_maxHight != null) {
            Rollingitem item = _maxHight.Next;
            while (item != null) {
                Rollingitem i = item.Next;
                item = null;
                item = i;
            }
        }

        _maxHight   = null;
        _minHight   = null;
        _oneItem    = null;

        _panel      = null;
        _view       = null;
    }
}

/// <summary>
/// 外部调用接口
/// </summary>
/// <typeparam name="T"></typeparam>
public class LoopDate<T> where T : Component {
    private LoopList _roll;

    public LoopList Roll { get { return _roll; } }

    #region 外部接口
    public delegate int GetCount();
    // 总数
    public GetCount Count;
    // 需要更新的  列  需要更新的数据索引
    public delegate void RanksInfo(T ranks, int index);
    /// <summary>
    /// 数据更新  
    /// </summary>
    public RanksInfo InfoDate;
    // 需要清空的列  ranks 列索引
    public delegate void ClaerDel(T ranks);

    /// <summary>
    ///  数据清除
    /// </summary>
    public ClaerDel claer;

    public delegate void UpdateDataDel();

    /// <summary>
    /// end
    /// </summary>
    public UpdateDataDel Data;
    #endregion
    /// <summary>
    /// 刷新列表
    /// </summary>
    //        public bool IsAuto;
    private int _lastIndex;

    public RoleList<T> LsRoll = new RoleList<T>();
    public LoopDate(Transform target) {

        _roll = target.GetOrAddComponent<LoopList>();
        _roll.OnStart();
        _roll.MoveChange = RollScroll;
    }

    public void Reset() {
        if (Count == null)
            return;

        _roll.View.onDragFinished = null;
        _roll.Reset();

        for (int i = 0; i < LsRoll.Count; i++) {
            if (claer != null)
                claer(LsRoll[i]);
        }

        LsRoll.LastIndex = 0;
        LsRoll.ShowNum = _roll.ViewNum;

        var num = Count() <= LsRoll.ShowNum + 1 ? Count() : LsRoll.ShowNum + 1;
        _lastIndex = num;

        for (int i = 0; i < num; i++)
            SetInfo(LsRoll[i], i);

    }

    private void SetInfo(T ranks, int index) {
        if (InfoDate != null) {
            InfoDate(ranks, index);
        }
    }
    public void UpdateData() {
        int minIndex = _roll.OneItem.Id + _roll.ViewNum + 1;

//        Debug.Log(minIndex);
        LoopList.Rollingitem roll = _roll.OneItem;

        _lastIndex = roll.Id;
//        while (roll.Id < _lastIndex) {
//            roll = roll.Next;
//            if (roll == null)
//                break;
//        }
        //Count() > _lastIndex &&
        while (_lastIndex <= minIndex && roll != null) {

            var info = LsRoll[roll.Vindex];
            if (Count() > _lastIndex && _lastIndex >= 0) {

                SetInfo(info, roll.Id);
                info.gameObject.SetActive(true);
            } else {
                claer(info);
            }

            roll = roll.Next;
            _lastIndex = roll.Id;
        }

    }

    private void RollScroll(LoopList.MoveType move, int claerIndex, int oneStart, int oneIndex, Transform target) {
        if (Count == null)
            return;

        if (claer != null) {
            var info = LsRoll[claerIndex];
            claer(info);
            info.gameObject.SetActive(false);
        }


        LsRoll[claerIndex].gameObject.SetActive(false);

        if (oneIndex >= 0 && oneIndex < Count()) {
            var info = LsRoll[oneStart];
            SetInfo(info, oneIndex);
            info.gameObject.SetActive(true);
        }

        int endindex = oneIndex + LsRoll.ShowNum;

        if (Count() <= endindex) {
            _lastIndex = endindex;

            if (Data != null)
                Data();
            return;
        }

        if (endindex < 0)
            return;

        var index = _roll.UpdateIndex(oneStart + LsRoll.ShowNum);
        var lastInfo = LsRoll[index];
        SetInfo(lastInfo, endindex);
        lastInfo.gameObject.SetActive(true);
    }

    public void Claer() {
        LsRoll.Clear();
        _roll.Clear();
    }
}


public class RoleList<T> : List<T> {
    public int LastIndex;
    public int ShowNum;
}